#include <iostream>
#include <sstream>
#include <assert.h>

#include "sequence_corpus_reader.h"

SequenceCorpusReader::SequenceCorpusReader(boost::shared_ptr<Parameters> p)
: myEOF(false)
{
	myInputFile.open(p->input_arg); 

	std::string buf;
	std::getline(myInputFile, buf);
	std::istringstream ss(buf);
	ss >> mySemiOrder >> myNumLabels;
}

SequenceCorpusReader::~SequenceCorpusReader()
{
	myInputFile.close();
}

SequenceCorpusReader::EntryPtr SequenceCorpusReader::next()
{
	EntryPtr result;
	
	try
	{
		result = get_tokens(myInputFile);
	}
	catch (std::ios_base::failure)
	{
		myEOF = true;
		return EntryPtr();
	}

	return result;
}

SequenceCorpusReader::EntryPtr
SequenceCorpusReader::get_tokens(igzstream &in)
{
	EntryPtr result(new Entry);
	
	std::string buf;
	std::getline(in, buf);
	std::istringstream ss(buf);

	// read start/end labels
	ss >> result->start_label >> result->end_label;

	// read segment labelling
	std::getline(in, buf);
	ss.clear();
	ss.str(buf);
	size_t label=0, start=0, end=0, sequence_end=0;
	while(ss >> start)
	{
		ss >> end >> label;
		if (!ss) 
		{
			std::cerr << "ERROR: invalid stream; semi-markov order may be too";
			std::cerr << " small for the data";
			assert(ss);
		}
		std::pair<size_t,size_t> s_index(start,end);
		(*result->gold)[s_index] = label;
		if (end > sequence_end) sequence_end = end;
	}

	// read features
	for (int i=0; i<(int)sequence_end; i++)
	{
		std::vector<std::set<std::string> > node_segments; 
		for (int j=0; i-j >= 0 && j < (int)mySemiOrder; j++)
		{
			std::getline(in, buf);
			ss.clear();
			ss.str(buf);
			std::set<std::string> features;
			std::string token;
			while(ss >> token)
			{
				features.insert(token);
			}
			node_segments.push_back(features);
		}	
		result->features_chart.push_back(node_segments);
	}

	// this is a HACK that needs a better solution
//	assert(result->features_chart.size() > 1);
	return result;
}

void SequenceCorpusReader::reset()
{

}

//std::ostream& operator<<(std::ostream &out, const SequenceCorpusReader::Segment &s)
//{
//	out << "(" << s.start << "," << s.end << ")" << "=" << s.label;
//	return out;
//}
//
std::ostream& operator<<(std::ostream &out, const SequenceCorpusReader::Entry& e)
{
	for (SequenceCorpusReader::SegmentLabelling::const_iterator it=e.gold->begin(); 
		it!=e.gold->end(); ++it)
		out << "(" << it->first.first << "," << it->first.second << ")=" 
			<< it->second << " ";
	out << "\n";
	for (size_t i=0; i<e.features_chart.size(); ++i)
	{
		for (size_t j=0; j<e.features_chart[i].size(); ++j)
		{
			for (std::set<std::string>::iterator it=e.features_chart[i][j].begin();
				it!=e.features_chart[i][j].end(); ++it)
					out << *it << " ";
			out << '\n';
		}
	}
	out << std::endl;

	return out;
}
